using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Rhino.Mocks;

using Lincolnwood.Foundation.Scheduling;
namespace Lincolnwood.Foundation.Scheduling.Tests
{
    [TestClass]
    public class WeeklyRecurrencePatternTests
    {
        private MockRepository mockMaker;

        [TestInitialize]
        public void Init()
        {
            mockMaker = new MockRepository();
        }

        [TestMethod]
        public void ExpandWeeklyRecurringEvent_UsingWindowThatEndsBeforeEventBegins_YieldsNoInstancesTest()
        {
            string testName = "Test Recurring Event";
            string testDesc =  "Event used for unit testing weekly recurring events during a window beginning before " +
                "the 1st event occurance and ending before the 1st event occurance";
            DateTime testStart = DateTime.Parse("1/1/2006 1:00 pm");  // when the event starts
            DateTime testEnd = DateTime.Parse("1/1/2006 5:00 pm");  // when the event ends

            DateTime expandWindowBegin = DateTime.Parse("1/1/1999"); // we will start expanding recurrences from
            DateTime expandWindowEnd = DateTime.Parse("12/10/1999"); // we will stop expanding recurrences on

            RecurrableEventDefinition mockEvent = mockMaker.StrictMock<RecurrableEventDefinition>();
            Expect.Call(mockEvent.Name).Return(testName).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.Description).Return(testDesc).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.StartTime).Return(testStart).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.EndTime).Return(testEnd).Repeat.AtLeastOnce();

            mockEvent.Replay();

            WeeklyRecurrencePattern testPattern = new WeeklyRecurrencePattern(DateTime.Parse("1/31/2006"), 1);

            // expand the occurances
            IList<IEventInstance> eventList = testPattern.Expand(mockEvent, expandWindowBegin, expandWindowEnd);

            // make sure that the recurrence got computed correctly
            Assert.AreEqual(0, eventList.Count);
        }

        [TestMethod]
        public void ExpandWeeklyRecurringEvent_UsingWindowThatBeginsDuringRecurrencePeriodAndEndsDuringRecurrencePeriodTest_YieldsSubsetOfInstancesTest()
        {
            string testName = "Test Recurring Event";
            string testDesc = "Event used for unit testing weekly recurring events during a window beginning during " +
                "the period of event occurance and ending during the period of event occurance";
            DateTime testStart = DateTime.Parse("1/1/2006 1:00 pm");  // when the event starts
            DateTime testEnd = DateTime.Parse("1/1/2006 5:00 pm");  // when the event ends

            DateTime expandWindowBegin = DateTime.Parse("1/5/2006"); // we will start expanding recurrences from
            DateTime expandWindowEnd = DateTime.Parse("1/26/2006"); // we will stop expanding recurrences on

            RecurrableEventDefinition mockEvent = mockMaker.StrictMock<RecurrableEventDefinition>();
            Expect.Call(mockEvent.Name).Return(testName).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.Description).Return(testDesc).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.StartTime).Return(testStart).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.EndTime).Return(testEnd).Repeat.AtLeastOnce();

            mockEvent.Replay();

            WeeklyRecurrencePattern testPattern = new WeeklyRecurrencePattern(DateTime.Parse("1/31/2006"), 1);

            // expand the occurances
            IList<IEventInstance> eventList = testPattern.Expand(mockEvent, expandWindowBegin, expandWindowEnd);

            // make sure that the recurrence got computed correctly
            Assert.AreEqual(3, eventList.Count);
        }

        [TestMethod]
        public void ExpandWeeklyRecurringEvent_UsingWindowThatBeginsDuringEventAndEndsAfterEventTest()
        {
            string testName = "Test Recurring Event";
            string testDesc = "Event used for unit testing weekly recurring events during a window beginning during the recurring event range " +
                "and ending after the recurring event ends.";
            DateTime testStart = DateTime.Parse("1/1/2006 1:00 pm");  // when the event starts
            DateTime testEnd = DateTime.Parse("1/31/2006 5:00 pm");  // when the event ends

            DateTime expandWindowBegin = DateTime.Parse("1/5/2006"); // we will start expanding recurrences from
            DateTime expandWindowEnd = DateTime.Parse("2/25/2006"); // we will stop expanding recurrences on

            RecurrableEventDefinition mockEvent = mockMaker.StrictMock<RecurrableEventDefinition>();
            Expect.Call(mockEvent.Name).Return(testName).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.Description).Return(testDesc).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.StartTime).Return(testStart).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.EndTime).Return(testEnd).Repeat.AtLeastOnce();

            mockEvent.Replay();

            WeeklyRecurrencePattern testPattern = new WeeklyRecurrencePattern(DateTime.Parse("1/31/2006"), 1);

            // expand the occurances
            IList<IEventInstance> eventList = testPattern.Expand(mockEvent, DateTime.Parse("1/5/2006"), DateTime.Parse("2/25/2006"));

            // make sure that the recurrence got computed correctly
            Assert.AreEqual(4, eventList.Count);
        }

        [TestMethod]
        public void ExpandWeeklyRecurringEvent_UsingWindowThatBeginsAndEndsAfterEventRecurrenceEndsAfterWindowTest()
        {
            string testName = "Test Recurring Event";
            string testDesc = "Event used for weekly unit testing recurring events during a window beginning after the recurring event range " +
                "and also ending after the recurring event range";
            DateTime testStart = DateTime.Parse("1/1/2006 1:00 pm");  // when the event starts
            DateTime testEnd = DateTime.Parse("1/31/2006 5:00 pm");  // when the event ends

            DateTime expandWindowBegin = DateTime.Parse("3/12/2006"); // we will start expanding recurrences from
            DateTime expandWindowEnd = DateTime.Parse("5/21/2006"); // we will stop expanding recurrences on

            RecurrableEventDefinition mockEvent = mockMaker.StrictMock<RecurrableEventDefinition>();
            Expect.Call(mockEvent.Name).Return(testName).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.Description).Return(testDesc).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.StartTime).Return(testStart).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.EndTime).Return(testEnd).Repeat.AtLeastOnce();

            mockEvent.Replay();

            WeeklyRecurrencePattern testPattern = new WeeklyRecurrencePattern(DateTime.Parse("1/31/2006"), 1);
           
            // expand the occurances
            IList<IEventInstance> eventList = testPattern.Expand(mockEvent, expandWindowBegin, expandWindowEnd);

            // make sure that the recurrence got computed correctly
            Assert.AreEqual(0, eventList.Count);
        }

        [TestMethod]
        public void ExpandRecurringEventWindowBeginBeforeEndAfterTest()
        {

            string testName = "Test Recurring Event";
            string testDesc = "Event used for unit testing weekly recurring events during a window beginning before the recurring event range " +
                "and ending after the recurring event range";
            DateTime testStart = DateTime.Parse("1/1/2006 1:00 pm");  // when the event starts
            DateTime testEnd = DateTime.Parse("1/31/2006 5:00 pm");  // when the event ends

            DateTime expandWindowBegin = DateTime.Parse("12/29/2005"); // we will start expanding recurrences from
            DateTime expandWindowEnd = DateTime.Parse("1/15/2007"); // we will stop expanding recurrences on

            RecurrableEventDefinition mockEvent = mockMaker.StrictMock<RecurrableEventDefinition>();
            Expect.Call(mockEvent.Name).Return(testName).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.Description).Return(testDesc).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.StartTime).Return(testStart).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.EndTime).Return(testEnd).Repeat.AtLeastOnce();

            mockEvent.Replay();

            WeeklyRecurrencePattern testPattern = new WeeklyRecurrencePattern(DateTime.Parse("1/31/2006"), 1);

            // expand the occurances
            IList<IEventInstance> eventList = testPattern.Expand(mockEvent, expandWindowBegin, expandWindowEnd);

            // make sure that the recurrence got computed correctly
            Assert.AreEqual(5, eventList.Count);
        }

        [TestMethod]
        public void ExpandRecurringEventWithDeletionException()
        {
            string testName = "Test Recurring Event";
            string testDesc = "Event used for unit testing weekly recurring events during a window beginning during " +
                "the period of event occurance and ending during the period of event occurance";
            DateTime testStart = DateTime.Parse("1/1/2006 1:00 pm");  // when the event starts
            DateTime testEnd = DateTime.Parse("1/1/2006 5:00 pm");  // when the event ends

            DateTime expandWindowBegin = DateTime.Parse("1/5/2006"); // we will start expanding recurrences from
            DateTime expandWindowEnd = DateTime.Parse("1/26/2006"); // we will stop expanding recurrences on
            DateTime instanceDateToRemove = DateTime.Parse("1/8/2006");

            RecurrableEventDefinition mockEvent = mockMaker.StrictMock<RecurrableEventDefinition>();
            Expect.Call(mockEvent.Name).Return(testName).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.Description).Return(testDesc).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.StartTime).Return(testStart).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.EndTime).Return(testEnd).Repeat.AtLeastOnce();

            mockEvent.Replay();

            WeeklyRecurrencePattern testPattern = new WeeklyRecurrencePattern(DateTime.Parse("1/31/2006"), 1);
         
            // remove one of the recurrences
            // remove one of the occurances 
            testPattern.RemoveInstance(instanceDateToRemove);
            
            // expand the occurances
            IList<IEventInstance> eventList = testPattern.Expand(mockEvent, expandWindowBegin, expandWindowEnd);

            // make sure that the recurrence got computed correctly
            Assert.AreEqual(2, eventList.Count);
        }

        [TestMethod]
        public void ExpandRecurringEventWithModificationException()
        {
            string testName = "Test Recurring Event";
            string testDesc = "Event used for unit testing weekly recurring events during a window beginning during " +
                "the period of event occurance and ending during the period of event occurance";
            DateTime testStart = DateTime.Parse("1/1/2006 1:00 pm");  // when the event starts
            DateTime testEnd = DateTime.Parse("1/1/2006 5:00 pm");  // when the event ends

            DateTime expandWindowBegin = DateTime.Parse("1/5/2006"); // we will start expanding recurrences from
            DateTime expandWindowEnd = DateTime.Parse("1/26/2006"); // we will stop expanding recurrences on
            DateTime instanceDateToModify = DateTime.Parse("1/8/2006");

            RecurrableEventDefinition mockEvent = mockMaker.StrictMock<RecurrableEventDefinition>();
            Expect.Call(mockEvent.Name).Return(testName).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.Description).Return(testDesc).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.StartTime).Return(testStart).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.EndTime).Return(testEnd).Repeat.AtLeastOnce();

            mockEvent.Replay();

            WeeklyRecurrencePattern testPattern = new WeeklyRecurrencePattern(DateTime.Parse("1/31/2006"), 1);


            // modify one of the recurrences
            var eventException = testPattern.AlterInstance(instanceDateToModify,
                            "test modified event",
                            "test modified event",
                            DateTime.Parse("1/8/2006 3:00 pm"),
                            DateTime.Parse("1/8/2006 6:00 pm"));

            // expand the occurances
            IList<IEventInstance> eventList = testPattern.Expand(mockEvent, DateTime.Parse("1/5/2006"), DateTime.Parse("1/26/2006"));

            // make sure that the recurrence got computed correctly
            Assert.AreEqual(3, eventList.Count);

            // make sure that our event exception got included
            var actualEventExceptions = (from i in eventList
                                         where i.StartTime == DateTime.Parse("1/8/2006 3:00 pm")
                                             && i.EndTime == DateTime.Parse("1/8/2006 6:00 pm")
                                         select i).Count<IEventInstance>();

            Assert.AreEqual(1, actualEventExceptions);
        }
    }
}
